import os
import json
import threading
from typing import Dict, List, Optional, Any
from .page import PageManager

class FileManager:
    """
    文件管理器，管理数据表到页集合的映射。
    设计决策：
      - 负责表与物理页的映射关系，支持表的创建、扩展、删除等操作。
      - 元数据持久化，保证系统重启后表与页的映射不丢失。
      - 通过组合PageManager实现页的分配与回收，解耦文件与页管理。
      - 预留表结构(schema)扩展点，便于后续支持复杂表结构和元数据。
      - 统一异常处理，便于调试和调用方异常捕获。
      - 支持并发控制，保证多线程环境下元数据一致性。
    """

    def __init__(self, meta_file: str = "file_meta.json", page_manager: PageManager = None):
        """
        初始化文件管理器

        Args:
            meta_file: 元数据文件路径
            page_manager: 页管理器实例
        """
        self.meta_file = meta_file
        self.page_manager = page_manager or PageManager()
        self.file_meta: Dict[str, Dict[str, Any]] = {}
        self._lock = threading.RLock()  # 并发控制锁，保证多线程安全
        self._load_meta()

    def _load_meta(self):
        """
        加载元数据，若文件不存在则初始化为空。
        设计说明：异常时自动恢复为空，保证系统健壮性。
        """
        with self._lock:
            if os.path.exists(self.meta_file):
                try:
                    with open(self.meta_file, 'r') as f:
                        self.file_meta = json.load(f)
                except Exception as e:
                    # 日志可扩展：print(f"Meta load error: {e}")
                    self.file_meta = {}
            else:
                self.file_meta = {}

    def _save_meta(self):
        """
        保存元数据到磁盘，保证表与页映射的持久性。
        """
        with self._lock:
            with open(self.meta_file, 'w') as f:
                json.dump(self.file_meta, f, indent=2)

    def create_table(self, table_name: str, initial_pages: int = 1) -> bool:
        """
        创建数据表，分配初始页并持久化元数据。
        若表已存在则返回False。
        支持原子性：分配失败时自动回滚。
        """
        with self._lock:
            if table_name in self.file_meta:
                return False  # 表已存在

            page_ids = []
            for _ in range(initial_pages):
                page_id = self._allocate_page_id()
                if not self.page_manager.allocate_page(page_id):
                    # 分配失败，回滚已分配的页
                    for pid in page_ids:
                        self.page_manager.release_page(pid)
                    return False
                page_ids.append(page_id)

            # 保存元数据，schema可扩展为表结构信息
            self.file_meta[table_name] = {
                "page_ids": page_ids,
                "schema": {}
            }
            self._save_meta()
            return True

    def delete_table(self, table_name: str) -> bool:
        """
        删除数据表，释放所有页并移除元数据。
        若表不存在返回False。
        """
        with self._lock:
            if table_name not in self.file_meta:
                return False

            # 释放所有页
            for page_id in self.file_meta[table_name]["page_ids"]:
                self.page_manager.release_page(page_id)

            # 删除元数据
            del self.file_meta[table_name]
            self._save_meta()
            return True

    def extend_table(self, table_name: str, num_pages: int = 1) -> List[int]:
        """
        扩展数据表，分配新页并更新元数据。
        支持原子性：分配失败时自动回滚。
        """
        with self._lock:
            if table_name not in self.file_meta:
                return []

            new_page_ids = []
            for _ in range(num_pages):
                page_id = self._allocate_page_id()
                if not self.page_manager.allocate_page(page_id):
                    # 分配失败，回滚已分配的页
                    for pid in new_page_ids:
                        self.page_manager.release_page(pid)
                    return []
                new_page_ids.append(page_id)

            self.file_meta[table_name]["page_ids"].extend(new_page_ids)
            self._save_meta()
            return new_page_ids

    def get_table_pages(self, table_name: str) -> List[int]:
        """
        获取数据表的所有页ID，表不存在返回空列表。
        """
        with self._lock:
            if table_name not in self.file_meta:
                return []
            return self.file_meta[table_name]["page_ids"]

    def _allocate_page_id(self) -> int:
        """
        分配一个新的页ID。
        设计说明：简单实现为当前最大页ID+1，后续可扩展为空闲页回收、位图管理等。
        """
        existing_ids = self.page_manager.get_all_page_ids()
        if not existing_ids:
            return 1
        return max(existing_ids) + 1

    def get_table_info(self, table_name: str) -> Optional[Dict[str, Any]]:
        """
        获取表信息（如页ID列表、表结构等），表不存在返回None。
        """
        with self._lock:
            return self.file_meta.get(table_name)

    def list_tables(self) -> List[str]:
        """
        获取所有表名，便于元数据管理和系统监控。
        """
        with self._lock:
            return list(self.file_meta.keys())
